package com.smartboot.plus.features.auth;

import com.smartboot.plus.features.NodeUtil;
import com.smartboot.plus.features.cluster.ClusterConnector;
import com.smartboot.plus.ignite.cache.MqttAuthCache;
import com.smartboot.plus.ignite.cache.MqttNodeCache;
import com.smartboot.plus.launch.LauncherService;
import com.smartboot.plus.service.MqttAuthService;
import com.smartboot.plus.service.MqttMessageService;
import com.smartboot.plus.service.MqttNodeService;
import com.smartboot.plus.utils.Func;
import com.smartboot.plus.utils.SecurePasswordUtil;
import org.apache.ignite.Ignite;
import org.smartboot.socket.transport.AioSession;
import tech.smartboot.feat.cloud.annotation.Autowired;
import tech.smartboot.feat.cloud.annotation.Bean;
import tech.smartboot.feat.cloud.annotation.PostConstruct;
import tech.smartboot.feat.core.common.logging.Logger;
import tech.smartboot.feat.core.common.logging.LoggerFactory;
import tech.smartboot.mqtt.common.enums.MqttConnectReturnCode;
import tech.smartboot.mqtt.common.message.MqttConnectMessage;
import tech.smartboot.mqtt.common.message.payload.MqttConnectPayload;
import tech.smartboot.mqtt.plugin.spec.BrokerContext;
import tech.smartboot.mqtt.plugin.spec.MqttSession;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * MQTT 认证功能类。
 * 实现客户端连接时的用户名密码校验与权限管理。
 */
@Bean
public class MqttAuthFeatures {
    private static final Logger LOGGER = LoggerFactory.getLogger(MqttAuthFeatures.class);

    @Autowired
    private Ignite igniteInstance;

    @Autowired
    private MqttMessageService mqttMessageService;

    @Autowired
    private MqttAuthService mqttAuthService;


    // 存储客户端 ID 与用户名的映射关系
    private final Map<String, String> mqttUser = new ConcurrentHashMap<>();


    @Autowired
    private BrokerContext brokerContext;

    @Autowired
    private MqttNodeService mqttNodeService;

    @Autowired
    private ClusterConnector clusterConnector;
    private String localNodeId;


    @PostConstruct
    public void init() {
        // 初始化逻辑
        localNodeId = NodeUtil.getNodeId(brokerContext);
    }

    /**
     * 处理客户端连接消息，进行用户名密码认证。
     *
     * @param session 客户端连接会话
     * @param message MQTT 连接消息
     * @return true 表示认证成功，false 表示失败
     */
    public boolean connectMessage(AioSession session, MqttConnectMessage message) {
        try {
            // 1. 解析消息载荷中的认证信息
            MqttConnectPayload payload = message.getPayload();
            String clientId = payload.clientId();
            String username = payload.userName();
            String rawPassword = new String(payload.passwordInBytes());

            // 2. 检查用户名和密码是否为空
            if (Func.isEmpty(username) || Func.isBlank(username)) {
                return handleAuthFailure(session, MqttConnectReturnCode.BAD_USERNAME_OR_PASSWORD);
            }
            if (Func.isEmpty(rawPassword) || Func.isBlank(rawPassword)) {
                return handleAuthFailure(session, MqttConnectReturnCode.BAD_USERNAME_OR_PASSWORD);
            }
            if (clientId.toUpperCase().startsWith("CLUSTER_HYB_")) {
                MqttNodeCache mqttNodeCache = mqttNodeService.selectOne(" nodeClientId='" + clientId + "' and clusterUsername='" + username + "'  and clusterPassword='" + rawPassword + "' ", MqttNodeCache.class);
                if (mqttNodeCache != null) {
                    // 3. 如果是集群节点连接，则进行集群节点认证
                    return true;
                } else {
                    return handleAuthFailure(session, MqttConnectReturnCode.CLIENT_IDENTIFIER_NOT_VALID);
                }
            }
            //认证
            if (isBaseAuth(username, rawPassword)) {
                mqttUser.put(clientId, username);
                return true;
            }

            // 4. 如基础认证未通过，则尝试缓存认证（数据库中配置的账号）
            MqttAuthCache mqttAuthCache = mqttAuthService.selectOne(" username='" + username + "' and status=0  ", MqttAuthCache.class);
            if (mqttAuthCache == null) {
                return handleAuthFailure(session, MqttConnectReturnCode.BAD_USERNAME_OR_PASSWORD);
            }
            // 加密密码校验
            String hashedPassword = SecurePasswordUtil.hashPassword(rawPassword, mqttAuthCache.getSalt(), mqttAuthCache.getEncryptionType(), mqttAuthCache.getSaltType());
            boolean check = username.equals(mqttAuthCache.getUsername()) && hashedPassword.equals(mqttAuthCache.getPassword());
            if (!check) {
                return handleAuthFailure(session, MqttConnectReturnCode.BAD_USERNAME_OR_PASSWORD);
            }

            // 5. 若存在相同 clientId 的连接，强制踢出
            mqttMessageService.getCacheGroup().ignite().message().send("disconnectTopic", clientId);
            // 6. 记录 clientId 与 username 映射，  MqttSession 中作者 三刀 不给加username 属性，所以自己绑定


            mqttUser.put(clientId, username);
            return true;


        } catch (Exception e) {
            LOGGER.error("MQTT认证异常", e);
            MqttSession.connFailAck(MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE, session.getAttachment());
            return false;
        }
    }


    /**
     * 基础认证逻辑：根据配置文件中定义的用户名和加密密码进行匹配
     */
    private boolean isBaseAuth(String username, String password) {
        String configUser = System.getProperty(LauncherService.CONFIG_AUTH_USER_NAME);
        String configPass = System.getProperty(LauncherService.CONFIG_AUTH_PASSWORD);
        String hashedPassword = SecurePasswordUtil.hashPassword(password, username + ":" + password, "SHA-512", "prefix");
        //  System.out.println(hashedPassword);
        return username.equals(configUser) && hashedPassword.equals(configPass);
    }

    /**
     * 处理认证失败：发送失败响应码
     */
    private boolean handleAuthFailure(AioSession session, MqttConnectReturnCode code) {
        MqttSession.connFailAck(code, session.getAttachment());
        return true;
    }

    /**
     * 获取当前所有 clientId 与 username 映射
     */
    public Map<String, String> getMqttUser() {
        return mqttUser;
    }
}